source('../settings/settings.R')
source('commonFunctions.R')
library(nlme)
library(lme4)
set.seed(43)
inputFileDrive1 <- str_interp("../data/processed/analysis/TT1_Drive_${drive}_PP_${distPrev}m_${distNext}m.csv", list(drive=1, distPrev=DISTANCE_PREV, distNext=DISTANCE_NEXT))
inputFileDrive2 <- str_interp("../data/processed/analysis/TT1_Drive_${drive}_PP_${distPrev}m_${distNext}m.csv", list(drive=2, distPrev=DISTANCE_PREV, distNext=DISTANCE_NEXT))
inputFileDrive3 <- str_interp("../data/processed/analysis/TT1_Drive_${drive}_PP_${distPrev}m_${distNext}m.csv", list(drive=3, distPrev=DISTANCE_PREV, distNext=DISTANCE_NEXT))
inputFileDrive4 <- str_interp("../data/processed/analysis/TT1_Drive_${drive}_PP_${distPrev}m_${distNext}m.csv", list(drive=4, distPrev=30, distNext=30))
drive1 <- read.csv(inputFileDrive1)
drive2 <- read.csv(inputFileDrive2)
drive3 <- read.csv(inputFileDrive3)
drive4 <- read.csv(inputFileDrive4, stringsAsFactors = T)
dfSeg <- data.frame(rep(1, nrow(drive4)), rep(2, nrow(drive4)), rep(3, nrow(drive4)), rep(4, nrow(drive4)))
names(dfSeg) <- c("Seg1", "Seg2", "Seg3", "Seg4")
combinedDf_Seg1 <- cbind(drive4,
drive1$MeanPP_Seg0,
drive2$MeanPP_Seg1, drive3$MeanPP_Seg1,
drive2$MeanPP_Seg0_1, drive3$MeanPP_Seg0_1,
drive2$StdPP_Seg1, drive3$StdPP_Seg1,
drive2$StdPP_Seg0_1, drive3$StdPP_Seg0_1,
drive2$MeanPP_AccHigh1, drive3$MeanPP_AccHigh1,
drive2$X.MeanPP_AccLow1, drive3$X.MeanPP_AccLow1,
drive2$StdPP_AccHigh1, drive3$StdPP_AccHigh1,
drive2$StdPP_AccLow1, drive3$StdPP_AccLow1,
dfSeg$Seg1
)
combinedDf_Seg2 <- cbind(drive4,
drive1$MeanPP_Seg0,
drive2$MeanPP_Seg2, drive3$MeanPP_Seg2,
drive2$MeanPP_Seg0_2, drive3$MeanPP_Seg0_2,
drive2$StdPP_Seg2, drive3$StdPP_Seg2,
drive2$StdPP_Seg0_2, drive3$StdPP_Seg0_2,
drive2$MeanPP_AccHigh2, drive3$MeanPP_AccHigh2,
drive2$X.MeanPP_AccLow2, drive3$X.MeanPP_AccLow2,
drive2$StdPP_AccHigh2, drive3$StdPP_AccHigh2,
drive2$StdPP_AccLow2, drive3$StdPP_AccLow2,
dfSeg$Seg2
)
combinedDf_Seg3 <- cbind(drive4,
drive1$MeanPP_Seg0,
drive2$MeanPP_Seg3, drive3$MeanPP_Seg3,
drive2$MeanPP_Seg0_3, drive3$MeanPP_Seg0_3,
drive2$StdPP_Seg3, drive3$StdPP_Seg3,
drive2$StdPP_Seg0_3, drive3$StdPP_Seg0_3,
drive2$MeanPP_AccHigh3, drive3$MeanPP_AccHigh3,
drive2$X.MeanPP_AccLow3, drive3$X.MeanPP_AccLow3,
drive2$StdPP_AccHigh3, drive3$StdPP_AccHigh3,
drive2$StdPP_AccLow3, drive3$StdPP_AccLow3,
dfSeg$Seg3
)
combinedDf_Seg4 <- cbind(drive4,
drive1$MeanPP_Seg0,
drive2$MeanPP_Seg4, drive3$MeanPP_Seg4,
drive2$MeanPP_Seg0_4, drive3$MeanPP_Seg0_4,
drive2$StdPP_Seg4, drive3$StdPP_Seg4,
drive2$StdPP_Seg0_4, drive3$StdPP_Seg0_4,
drive2$MeanPP_AccHigh4, drive3$MeanPP_AccHigh4,
drive2$X.MeanPP_AccLow4, drive3$X.MeanPP_AccLow4,
drive2$StdPP_AccHigh4, drive3$StdPP_AccHigh4,
drive2$StdPP_AccLow4, drive3$StdPP_AccLow4,
dfSeg$Seg4
)
common_names <- c("PP_Dev_1_Turning",
"PP_Dev_2_Straight", "PP_Dev_3_Straight",
"PP_Dev_2_Turning", "PP_Dev_3_Turning",
"Std_PP_2_Straight", "Std_PP_3_Straight",
"Std_PP_2_Turning", "Std_PP_3_Turning",
"Mean_PP_2_AccHigh", "Mean_PP_3_AccHigh",
"Mean_PP_2_AccLow", "Mean_PP_3_AccLow",
"Std_PP_2_AccHigh", "Std_PP_3_AccHigh",
"Std_PP_2_AccLow", "Std_PP_3_AccLow",
"Segment")
names(combinedDf_Seg1) <- c(names(drive4), common_names)
names(combinedDf_Seg2) <- c(names(drive4), common_names)
names(combinedDf_Seg3) <- c(names(drive4), common_names)
names(combinedDf_Seg4) <- c(names(drive4), common_names)
# combinedDf_Seg1$Subject <- paste0(as.factor(combinedDf_Seg1$Subject), ".S1")
# combinedDf_Seg2$Subject <- paste0(as.factor(combinedDf_Seg2$Subject), ".S2")
# combinedDf_Seg3$Subject <- paste0(as.factor(combinedDf_Seg3$Subject), ".S3")
# combinedDf_Seg4$Subject <- paste0(as.factor(combinedDf_Seg4$Subject), ".S4")
combinedDf <- rbind(combinedDf_Seg1, combinedDf_Seg2, combinedDf_Seg3, combinedDf_Seg4)
# combinedDf$Subject <- paste0("#", str_pad(combinedDf$Subject, 2, pad="0"))
combinedDf$Segment <- as.factor(combinedDf$Segment)
combinedDf$ActivityEncoded <- factor(ifelse(combinedDf$Activity == "NO", "1", ifelse(combinedDf$Activity == "C", "2", "3")))
combinedDf <- combinedDf[complete.cases(combinedDf),]
combinedDf$Subject = as.factor(combinedDf$Subject)
model = lm(PP_After ~
PP_Dev_2_Straight +
PP_Dev_3_Straight +
PP_Dev_2_Turning +
PP_Dev_3_Turning +
Std_PP_2_Straight +
Std_PP_3_Straight +
Std_PP_2_Turning +
Std_PP_3_Turning +
# PP_Prior +
factor(ActivityEncoded),
data=combinedDf, random = ~1|factor(Subject), method = "REML")
method = 'REML' is not supported. Using 'qr'In lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) :
extra argument ‘random’ will be disregarded
# anova(model)
summary(model)
Call:
lm(formula = PP_After ~ PP_Dev_2_Straight + PP_Dev_3_Straight +
PP_Dev_2_Turning + PP_Dev_3_Turning + Std_PP_2_Straight +
Std_PP_3_Straight + Std_PP_2_Turning + Std_PP_3_Turning +
factor(ActivityEncoded), data = combinedDf, method = "REML",
random = ~1 | factor(Subject))
Residuals:
Min 1Q Median 3Q Max
-0.17764 -0.07137 0.00092 0.05144 0.34502
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.02294 0.04870 -0.471 0.6393
PP_Dev_2_Straight 0.68712 0.15583 4.410 4.45e-05 ***
PP_Dev_3_Straight -0.37734 0.23618 -1.598 0.1155
PP_Dev_2_Turning -0.22015 0.14683 -1.499 0.1391
PP_Dev_3_Turning 0.38632 0.22101 1.748 0.0857 .
Std_PP_2_Straight 0.02144 0.38757 0.055 0.9561
Std_PP_3_Straight 0.50369 0.36818 1.368 0.1765
Std_PP_2_Turning -0.08343 0.50205 -0.166 0.8686
Std_PP_3_Turning -0.95800 0.60836 -1.575 0.1207
factor(ActivityEncoded)2 0.08647 0.03285 2.633 0.0108 *
factor(ActivityEncoded)3 0.17032 0.03184 5.349 1.51e-06 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.0993 on 59 degrees of freedom
Multiple R-squared: 0.5613, Adjusted R-squared: 0.4869
F-statistic: 7.548 on 10 and 59 DF, p-value: 1.338e-07
plot(model)




No Random Effects
linearModel1 <- lm(PP_After ~
Mean_PP_2_AccHigh
+ Mean_PP_2_AccLow
+ Mean_PP_3_AccHigh
+ Mean_PP_3_AccLow
+ Std_PP_2_AccHigh
+ Std_PP_2_AccLow
+ Std_PP_3_AccHigh
+ Std_PP_3_AccLow
# + PP_Prior
+ factor(ActivityEncoded),
data=combinedDf)
# anova(model)
summary(linearModel1)
Call:
lm(formula = PP_After ~ Mean_PP_2_AccHigh + Mean_PP_2_AccLow +
Mean_PP_3_AccHigh + Mean_PP_3_AccLow + Std_PP_2_AccHigh +
Std_PP_2_AccLow + Std_PP_3_AccHigh + Std_PP_3_AccLow + factor(ActivityEncoded),
data = combinedDf)
Residuals:
Min 1Q Median 3Q Max
-0.143483 -0.066038 -0.007552 0.051595 0.300313
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.06552 0.03640 -1.800 0.07695 .
Mean_PP_2_AccHigh 1.63376 0.50590 3.229 0.00203 **
Mean_PP_2_AccLow -1.15253 0.49763 -2.316 0.02405 *
Mean_PP_3_AccHigh 0.74436 0.31520 2.362 0.02152 *
Mean_PP_3_AccLow -0.66142 0.33913 -1.950 0.05589 .
Std_PP_2_AccHigh -1.28974 1.45755 -0.885 0.37982
Std_PP_2_AccLow 0.79583 1.15728 0.688 0.49435
Std_PP_3_AccHigh 0.15278 0.94374 0.162 0.87195
Std_PP_3_AccLow 0.91693 0.83810 1.094 0.27838
factor(ActivityEncoded)2 0.08724 0.03041 2.869 0.00571 **
factor(ActivityEncoded)3 0.14810 0.03043 4.867 8.83e-06 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.09353 on 59 degrees of freedom
Multiple R-squared: 0.6108, Adjusted R-squared: 0.5448
F-statistic: 9.259 on 10 and 59 DF, p-value: 5.37e-09
plot(linearModel1)




With Random Effects
linearModel1 <- lmer(PP_After ~
(1 | Subject)
+ Mean_PP_2_AccHigh
+ Mean_PP_2_AccLow
+ Mean_PP_3_AccHigh
+ Mean_PP_3_AccLow
+ Std_PP_2_AccHigh
+ Std_PP_2_AccLow
+ Std_PP_3_AccHigh
+ Std_PP_3_AccLow,
# + factor(ActivityEncoded),
data=combinedDf, REML = T)
Model failed to converge with max|grad| = 0.0670118 (tol = 0.002, component 1)Model is nearly unidentifiable: very large eigenvalue
- Rescale variables?Model may not have converged with 1 eigenvalue close to zero: 1.1e-10
# anova(model)
summary(linearModel1)
Linear mixed model fit by REML. t-tests use Satterthwaite's method ['lmerModLmerTest']
Formula: PP_After ~ (1 | Subject) + Mean_PP_2_AccHigh + Mean_PP_2_AccLow +
Mean_PP_3_AccHigh + Mean_PP_3_AccLow + Std_PP_2_AccHigh + Std_PP_2_AccLow + Std_PP_3_AccHigh + Std_PP_3_AccLow
Data: combinedDf
REML criterion at convergence: -1503.4
Scaled residuals:
Min 1Q Median 3Q Max
-4.063e-07 -1.190e-07 -6.100e-09 1.335e-07 6.294e-07
Random effects:
Groups Name Variance Std.Dev.
Subject (Intercept) 7.124e-03 8.440e-02
Residual 2.068e-17 4.548e-09
Number of obs: 70, groups: Subject, 21
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 8.333e-02 2.203e-02 7.891e-05 3.783 0.999
Mean_PP_2_AccHigh 6.340e-14 5.153e-08 7.891e-05 0.000 1.000
Mean_PP_2_AccLow -3.925e-14 3.923e-08 7.891e-05 0.000 1.000
Mean_PP_3_AccHigh -1.859e-15 1.820e-08 7.891e-05 0.000 1.000
Mean_PP_3_AccLow 6.079e-15 2.337e-08 7.891e-05 0.000 1.000
Std_PP_2_AccHigh 1.459e-14 8.442e-08 7.891e-05 0.000 1.000
Std_PP_2_AccLow 1.525e-16 6.425e-08 7.891e-05 0.000 1.000
Std_PP_3_AccHigh -2.153e-14 5.689e-08 7.891e-05 0.000 1.000
Std_PP_3_AccLow 2.408e-14 4.744e-08 7.891e-05 0.000 1.000
Correlation of Fixed Effects:
(Intr) M_PP_2_AH M_PP_2_AL M_PP_3_AH M_PP_3_AL S_PP_2_AH S_PP_2_AL S_PP_3_AH
Mn_PP_2_AcH 0.000
Mn_PP_2_AcL 0.000 -0.960
Mn_PP_3_AcH 0.000 0.005 -0.029
Mn_PP_3_AcL 0.000 -0.055 0.015 -0.697
Std_PP_2_AH 0.000 0.147 -0.186 0.088 -0.073
Std_PP_2_AL 0.000 0.030 -0.013 -0.131 0.089 -0.877
Std_PP_3_AH 0.000 0.063 -0.115 -0.453 0.312 -0.339 0.190
Std_PP_3_AL 0.000 0.205 -0.222 0.376 -0.327 0.307 -0.236 -0.528
convergence code: 0
Model failed to converge with max|grad| = 0.0670118 (tol = 0.002, component 1)
Model is nearly unidentifiable: very large eigenvalue
- Rescale variables?
plot(linearModel1)

linearModel1 <- lm(PP_After ~
Mean_PP_2_AccHigh
+ Mean_PP_2_AccLow
+ Mean_PP_3_AccHigh
+ Mean_PP_3_AccLow
# + PP_Prior
+ factor(ActivityEncoded),
data=combinedDf)
# anova(model)
summary(linearModel1)
Call:
lm(formula = PP_After ~ Mean_PP_2_AccHigh + Mean_PP_2_AccLow +
Mean_PP_3_AccHigh + Mean_PP_3_AccLow + factor(ActivityEncoded),
data = combinedDf)
Residuals:
Min 1Q Median 3Q Max
-0.14161 -0.06916 -0.00742 0.04809 0.30760
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.05248 0.02751 -1.907 0.06103 .
Mean_PP_2_AccHigh 1.64939 0.38841 4.246 7.28e-05 ***
Mean_PP_2_AccLow -1.14578 0.37518 -3.054 0.00331 **
Mean_PP_3_AccHigh 0.65161 0.26162 2.491 0.01540 *
Mean_PP_3_AccLow -0.60534 0.28421 -2.130 0.03709 *
factor(ActivityEncoded)2 0.08906 0.02976 2.993 0.00394 **
factor(ActivityEncoded)3 0.15955 0.02892 5.516 6.92e-07 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.09303 on 63 degrees of freedom
Multiple R-squared: 0.5888, Adjusted R-squared: 0.5496
F-statistic: 15.03 on 6 and 63 DF, p-value: 1.372e-10
plot(linearModel1)




Machine Learning
ppAfter <- combinedDf$PP_After
ppAfterArray <- matrix(ppAfter, nrow = 1,ncol = length(ppAfter))
thresholdPPAfter <- otsu(ppAfterArray, range=c(min(ppAfter), max(ppAfter))) # Expected Threshold > 0.10123
print(paste0('Threshold: ', thresholdPPAfter))
[1] "Threshold: 0.101235546875"
selectedDf <- combinedDf %>% select(
"Subject", "Activity", "PP_After", # "PP_Prior",
"Mean_PP_2_AccHigh", "Mean_PP_3_AccHigh",
"Mean_PP_2_AccLow", "Mean_PP_3_AccLow",
"Std_PP_2_AccHigh", "Std_PP_3_AccHigh",
"Std_PP_2_AccLow", "Std_PP_3_AccLow")
selectedDf$Subject <- NULL
selectedDf$Activity_NO <- ifelse(selectedDf$Activity == "NO", 1, 0)
selectedDf$Activity_C <- ifelse(selectedDf$Activity == "C", 1, 0)
selectedDf$Activity_M <- ifelse(selectedDf$Activity == "M", 1, 0)
selectedDf$Activity <- NULL
# selectedDf$PP_Dev_1_Turning <- NULL
# selectedDf$Std_PP_2_Straight <- NULL
# selectedDf$Std_PP_2_Turning <- NULL
# selectedDf$Std_PP_3_Straight <- NULL
# selectedDf$Std_PP_3_Turning <- NULL
#
# # According to Linear model
# selectedDf$PP_Dev_2_Straight <- abs(selectedDf$PP_Dev_2_Straight)
# selectedDf$PP_Dev_3_Straight <- abs(selectedDf$PP_Dev_3_Straight)
# selectedDf$PP_Dev_2_Turning <- abs(selectedDf$PP_Dev_2_Turning)
# selectedDf$PP_Dev_3_Turning <- abs(selectedDf$PP_Dev_3_Turning)
# selectedDf$PP_Prior <- abs(selectedDf$PP_Prior) # NULL
selectedDf$Class <- ifelse(selectedDf$PP_After >= thresholdPPAfter, T, F)
selectedDf$PP_After <- NULL
print(names(selectedDf))
[1] "Mean_PP_2_AccHigh" "Mean_PP_3_AccHigh" "Mean_PP_2_AccLow" "Mean_PP_3_AccLow" "Std_PP_2_AccHigh" "Std_PP_3_AccHigh"
[7] "Std_PP_2_AccLow" "Std_PP_3_AccLow" "Activity_NO" "Activity_C" "Activity_M" "Class"
# library(mefa)
# combinedDf <- rep(combinedDf, 10)
set.seed(39)
n_folds <- 10
params <- param <- list(objective = "binary:logistic",
booster = "gbtree",
eval_metric = "auc",
eta = 0.1,
max_depth = 10,
alpha = 1,
lambda = 0,
gamma = 0.45,
min_child_weight = 0.3,
subsample = 1,
colsample_bytree = 1)
# XGBoost Model
xgb_m <- xgb.cv( params = param,
data = as.matrix(selectedDf %>% select(-Class)) ,
label = selectedDf$Class,
nrounds = 100,
verbose = F,
prediction = T,
maximize = F, # Change this value to F will help to run with more itineration
nfold = n_folds,
metrics = c("auc", "error"),
early_stopping_rounds = 50,
stratified = T,
scale_pos_weight = 1)
# xgb_m$evaluation_log[xgb_m$best_iteration,"test_auc_mean"]
xgb_m$evaluation_log[xgb_m$best_iteration,]
NA
Performance Metrics
# Prediction
selectedDf$clsPred <- round(xgb_m$pred)
computePerformanceResults <- function(sdat){
sdat = sdat[complete.cases(sdat),]
acc = sum(sdat[,1] == sdat[,2])/nrow(sdat)
conf_mat = table(sdat)
specif = conf_mat[1,1]/sum(conf_mat[,1])
sensiv = conf_mat[2,2]/sum(conf_mat[,2])
preci = conf_mat[2,2]/sum(conf_mat[2,])
npv = conf_mat[1,1]/sum(conf_mat[1,])
return(c(acc,specif,sensiv,preci,npv))
}
# Get average performance
performance <- computePerformanceResults(selectedDf %>% select(Class, clsPred))
acc <- performance[1]
prec <- performance[4]
recall <- performance[3]
spec <- performance[2]
npv <- performance[5]
f1 <- (2 * recall * prec) / (recall + prec)
auc <- as.numeric(xgb_m$evaluation_log[xgb_m$best_iteration, "test_auc_mean"])
print(paste("Accuracy=", round(acc, 2)))
[1] "Accuracy= 0.81"
print(paste("Precision=", round(prec, 2)))
[1] "Precision= 0.7"
print(paste("Recall=", round(recall, 2)))
[1] "Recall= 0.84"
print(paste("Specificity=", round(spec, 2)))
[1] "Specificity= 0.8"
print(paste("NPV=", round(npv, 2)))
[1] "NPV= 0.9"
print(paste("F1=", round(f1, 2)))
[1] "F1= 0.76"
print(paste("AUC=", round(auc, 2)))
[1] "AUC= 0.9"
# Importance
bst <- xgboost( params = param,
data = as.matrix(selectedDf %>% select(-c(Class, clsPred))) ,
label = selectedDf$Class,
nrounds = 100,
verbose = F,
prediction = T,
maximize = F, # Change this value to F will help to run with more itineration
nfold = n_folds,
metrics = c("auc", "error"),
early_stopping_rounds = 50,
stratified = T,
scale_pos_weight = 1)
importanceDf <- xgb.importance(colnames(selectedDf %>% select(-c(Class, clsPred))), model = bst)
print(importanceDf)
library(pROC)
dfROC <- pROC::roc(response = ifelse(selectedDf$Class==T, 1, 0),
predictor = round(xgb_m$pred),
levels=c(0, 1), direction = "<")
# it = which.max(xgb_m$evaluation_log$test_auc_mean)
# best.iter = xgb_m$evaluation_log$iter[it]
# best.iter
plot(pROC::roc(response = ifelse(selectedDf$Class==T, 1, 0),
predictor = round(xgb_m$pred),
levels=c(0, 1), direction = "<"),
legacy.axes = TRUE,
main="ROC Curve",
lwd=1.5)

Plot feature importance
yAxis <- list(
title = 'Importance',
range=c(0.0, 1.0)
)
xAxis <- list(
title = ''
)
importanceDf$Feature <- factor(importanceDf$Feature, levels = importanceDf[order(-Gain),]$Feature)
fig_Importance <- plot_ly(importanceDf, x = ~Feature, y = ~Gain, type = 'bar', name = 'Gain', width=600) %>%
add_trace(y = ~Cover, name = 'Cover') %>%
add_trace(y = ~Frequency, name = 'Frequency') %>%
layout(yaxis = yAxis, xaxis=xAxis, barmode = 'group', title="Feature Importance") %>%
config(.Last.value, mathjax = 'cdn')
htmltools::tagList(fig_Importance)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CnNvdXJjZSgnLi4vc2V0dGluZ3Mvc2V0dGluZ3MuUicpCnNvdXJjZSgnY29tbW9uRnVuY3Rpb25zLlInKQpsaWJyYXJ5KG5sbWUpCmxpYnJhcnkobG1lNCkKYGBgCgpgYGB7cn0Kc2V0LnNlZWQoNDMpCmlucHV0RmlsZURyaXZlMSA8LSBzdHJfaW50ZXJwKCIuLi9kYXRhL3Byb2Nlc3NlZC9hbmFseXNpcy9UVDFfRHJpdmVfJHtkcml2ZX1fUFBfJHtkaXN0UHJldn1tXyR7ZGlzdE5leHR9bS5jc3YiLCBsaXN0KGRyaXZlPTEsIGRpc3RQcmV2PURJU1RBTkNFX1BSRVYsIGRpc3ROZXh0PURJU1RBTkNFX05FWFQpKQppbnB1dEZpbGVEcml2ZTIgPC0gc3RyX2ludGVycCgiLi4vZGF0YS9wcm9jZXNzZWQvYW5hbHlzaXMvVFQxX0RyaXZlXyR7ZHJpdmV9X1BQXyR7ZGlzdFByZXZ9bV8ke2Rpc3ROZXh0fW0uY3N2IiwgbGlzdChkcml2ZT0yLCBkaXN0UHJldj1ESVNUQU5DRV9QUkVWLCBkaXN0TmV4dD1ESVNUQU5DRV9ORVhUKSkKaW5wdXRGaWxlRHJpdmUzIDwtIHN0cl9pbnRlcnAoIi4uL2RhdGEvcHJvY2Vzc2VkL2FuYWx5c2lzL1RUMV9Ecml2ZV8ke2RyaXZlfV9QUF8ke2Rpc3RQcmV2fW1fJHtkaXN0TmV4dH1tLmNzdiIsIGxpc3QoZHJpdmU9MywgZGlzdFByZXY9RElTVEFOQ0VfUFJFViwgZGlzdE5leHQ9RElTVEFOQ0VfTkVYVCkpCmlucHV0RmlsZURyaXZlNCA8LSBzdHJfaW50ZXJwKCIuLi9kYXRhL3Byb2Nlc3NlZC9hbmFseXNpcy9UVDFfRHJpdmVfJHtkcml2ZX1fUFBfJHtkaXN0UHJldn1tXyR7ZGlzdE5leHR9bS5jc3YiLCBsaXN0KGRyaXZlPTQsIGRpc3RQcmV2PTMwLCBkaXN0TmV4dD0zMCkpCgpkcml2ZTEgPC0gcmVhZC5jc3YoaW5wdXRGaWxlRHJpdmUxKQpkcml2ZTIgPC0gcmVhZC5jc3YoaW5wdXRGaWxlRHJpdmUyKQpkcml2ZTMgPC0gcmVhZC5jc3YoaW5wdXRGaWxlRHJpdmUzKQoKZHJpdmU0IDwtIHJlYWQuY3N2KGlucHV0RmlsZURyaXZlNCwgc3RyaW5nc0FzRmFjdG9ycyA9IFQpCmBgYAoKYGBge3J9CmRmU2VnIDwtIGRhdGEuZnJhbWUocmVwKDEsIG5yb3coZHJpdmU0KSksIHJlcCgyLCBucm93KGRyaXZlNCkpLCByZXAoMywgbnJvdyhkcml2ZTQpKSwgcmVwKDQsIG5yb3coZHJpdmU0KSkpCm5hbWVzKGRmU2VnKSA8LSBjKCJTZWcxIiwgIlNlZzIiLCAiU2VnMyIsICJTZWc0IikKCmNvbWJpbmVkRGZfU2VnMSA8LSBjYmluZChkcml2ZTQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMSRNZWFuUFBfU2VnMCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWcxLCBkcml2ZTMkTWVhblBQX1NlZzEsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMF8xLCBkcml2ZTMkTWVhblBQX1NlZzBfMSwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnMSwgZHJpdmUzJFN0ZFBQX1NlZzEsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzBfMSwgZHJpdmUzJFN0ZFBQX1NlZzBfMSwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX0FjY0hpZ2gxLCBkcml2ZTMkTWVhblBQX0FjY0hpZ2gxLAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRYLk1lYW5QUF9BY2NMb3cxLCBkcml2ZTMkWC5NZWFuUFBfQWNjTG93MSwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjSGlnaDEsIGRyaXZlMyRTdGRQUF9BY2NIaWdoMSwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjTG93MSwgZHJpdmUzJFN0ZFBQX0FjY0xvdzEsCiAgICAgICAgICAgICAgICAgICAgZGZTZWckU2VnMQogICAgICAgICAgICAgICAgICApCmNvbWJpbmVkRGZfU2VnMiA8LSBjYmluZChkcml2ZTQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMSRNZWFuUFBfU2VnMCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWcyLCBkcml2ZTMkTWVhblBQX1NlZzIsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMF8yLCBkcml2ZTMkTWVhblBQX1NlZzBfMiwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnMiwgZHJpdmUzJFN0ZFBQX1NlZzIsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzBfMiwgZHJpdmUzJFN0ZFBQX1NlZzBfMiwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX0FjY0hpZ2gyLCBkcml2ZTMkTWVhblBQX0FjY0hpZ2gyLAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRYLk1lYW5QUF9BY2NMb3cyLCBkcml2ZTMkWC5NZWFuUFBfQWNjTG93MiwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjSGlnaDIsIGRyaXZlMyRTdGRQUF9BY2NIaWdoMiwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjTG93MiwgZHJpdmUzJFN0ZFBQX0FjY0xvdzIsCiAgICAgICAgICAgICAgICAgICAgZGZTZWckU2VnMgogICAgICAgICAgICAgICAgICApCmNvbWJpbmVkRGZfU2VnMyA8LSBjYmluZChkcml2ZTQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMSRNZWFuUFBfU2VnMCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWczLCBkcml2ZTMkTWVhblBQX1NlZzMsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMF8zLCBkcml2ZTMkTWVhblBQX1NlZzBfMywKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnMywgZHJpdmUzJFN0ZFBQX1NlZzMsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzBfMywgZHJpdmUzJFN0ZFBQX1NlZzBfMywKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX0FjY0hpZ2gzLCBkcml2ZTMkTWVhblBQX0FjY0hpZ2gzLAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRYLk1lYW5QUF9BY2NMb3czLCBkcml2ZTMkWC5NZWFuUFBfQWNjTG93MywKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjSGlnaDMsIGRyaXZlMyRTdGRQUF9BY2NIaWdoMywKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjTG93MywgZHJpdmUzJFN0ZFBQX0FjY0xvdzMsCiAgICAgICAgICAgICAgICAgICAgZGZTZWckU2VnMwogICAgICAgICAgICAgICAgICApCmNvbWJpbmVkRGZfU2VnNCA8LSBjYmluZChkcml2ZTQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMSRNZWFuUFBfU2VnMCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWc0LCBkcml2ZTMkTWVhblBQX1NlZzQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMF80LCBkcml2ZTMkTWVhblBQX1NlZzBfNCwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnNCwgZHJpdmUzJFN0ZFBQX1NlZzQsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzBfNCwgZHJpdmUzJFN0ZFBQX1NlZzBfNCwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX0FjY0hpZ2g0LCBkcml2ZTMkTWVhblBQX0FjY0hpZ2g0LAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRYLk1lYW5QUF9BY2NMb3c0LCBkcml2ZTMkWC5NZWFuUFBfQWNjTG93NCwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjSGlnaDQsIGRyaXZlMyRTdGRQUF9BY2NIaWdoNCwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjTG93NCwgZHJpdmUzJFN0ZFBQX0FjY0xvdzQsCiAgICAgICAgICAgICAgICAgICAgZGZTZWckU2VnNAogICAgICAgICAgICAgICAgICApCgpjb21tb25fbmFtZXMgPC0gYygiUFBfRGV2XzFfVHVybmluZyIsCiAgICAgICAgICAgICAgICAgICJQUF9EZXZfMl9TdHJhaWdodCIsICJQUF9EZXZfM19TdHJhaWdodCIsIAogICAgICAgICAgICAgICAgICAiUFBfRGV2XzJfVHVybmluZyIsICJQUF9EZXZfM19UdXJuaW5nIiwgCiAgICAgICAgICAgICAgICAgICJTdGRfUFBfMl9TdHJhaWdodCIsICJTdGRfUFBfM19TdHJhaWdodCIsIAogICAgICAgICAgICAgICAgICAiU3RkX1BQXzJfVHVybmluZyIsICJTdGRfUFBfM19UdXJuaW5nIiwKICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICJNZWFuX1BQXzJfQWNjSGlnaCIsICJNZWFuX1BQXzNfQWNjSGlnaCIsCiAgICAgICAgICAgICAgICAgICJNZWFuX1BQXzJfQWNjTG93IiwgIk1lYW5fUFBfM19BY2NMb3ciLAogICAgICAgICAgICAgICAgICAiU3RkX1BQXzJfQWNjSGlnaCIsICJTdGRfUFBfM19BY2NIaWdoIiwKICAgICAgICAgICAgICAgICAgIlN0ZF9QUF8yX0FjY0xvdyIsICJTdGRfUFBfM19BY2NMb3ciLAogICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgIlNlZ21lbnQiKQoKbmFtZXMoY29tYmluZWREZl9TZWcxKSA8LSBjKG5hbWVzKGRyaXZlNCksIGNvbW1vbl9uYW1lcykKbmFtZXMoY29tYmluZWREZl9TZWcyKSA8LSBjKG5hbWVzKGRyaXZlNCksIGNvbW1vbl9uYW1lcykKbmFtZXMoY29tYmluZWREZl9TZWczKSA8LSBjKG5hbWVzKGRyaXZlNCksIGNvbW1vbl9uYW1lcykKbmFtZXMoY29tYmluZWREZl9TZWc0KSA8LSBjKG5hbWVzKGRyaXZlNCksIGNvbW1vbl9uYW1lcykKCiMgY29tYmluZWREZl9TZWcxJFN1YmplY3QgPC0gcGFzdGUwKGFzLmZhY3Rvcihjb21iaW5lZERmX1NlZzEkU3ViamVjdCksICIuUzEiKQojIGNvbWJpbmVkRGZfU2VnMiRTdWJqZWN0IDwtIHBhc3RlMChhcy5mYWN0b3IoY29tYmluZWREZl9TZWcyJFN1YmplY3QpLCAiLlMyIikKIyBjb21iaW5lZERmX1NlZzMkU3ViamVjdCA8LSBwYXN0ZTAoYXMuZmFjdG9yKGNvbWJpbmVkRGZfU2VnMyRTdWJqZWN0KSwgIi5TMyIpCiMgY29tYmluZWREZl9TZWc0JFN1YmplY3QgPC0gcGFzdGUwKGFzLmZhY3Rvcihjb21iaW5lZERmX1NlZzQkU3ViamVjdCksICIuUzQiKQoKY29tYmluZWREZiA8LSByYmluZChjb21iaW5lZERmX1NlZzEsIGNvbWJpbmVkRGZfU2VnMiwgY29tYmluZWREZl9TZWczLCBjb21iaW5lZERmX1NlZzQpCgojIGNvbWJpbmVkRGYkU3ViamVjdCA8LSBwYXN0ZTAoIiMiLCBzdHJfcGFkKGNvbWJpbmVkRGYkU3ViamVjdCwgMiwgcGFkPSIwIikpCmNvbWJpbmVkRGYkU2VnbWVudCA8LSBhcy5mYWN0b3IoY29tYmluZWREZiRTZWdtZW50KQpjb21iaW5lZERmJEFjdGl2aXR5RW5jb2RlZCA8LSBmYWN0b3IoaWZlbHNlKGNvbWJpbmVkRGYkQWN0aXZpdHkgPT0gIk5PIiwgIjEiLCBpZmVsc2UoY29tYmluZWREZiRBY3Rpdml0eSA9PSAiQyIsICIyIiwgIjMiKSkpCgpjb21iaW5lZERmIDwtIGNvbWJpbmVkRGZbY29tcGxldGUuY2FzZXMoY29tYmluZWREZiksXQpjb21iaW5lZERmJFN1YmplY3QgPSBhcy5mYWN0b3IoY29tYmluZWREZiRTdWJqZWN0KQpgYGAKCgpgYGB7cn0KbW9kZWwgPSBsbShQUF9BZnRlciB+IAogICAgICAgICAgICAgIFBQX0Rldl8yX1N0cmFpZ2h0ICsgCiAgICAgICAgICAgICAgUFBfRGV2XzNfU3RyYWlnaHQgKwogICAgICAgICAgICAgIFBQX0Rldl8yX1R1cm5pbmcgKyAKICAgICAgICAgICAgICBQUF9EZXZfM19UdXJuaW5nICsgCiAgICAgICAgICAgICAgU3RkX1BQXzJfU3RyYWlnaHQgKyAKICAgICAgICAgICAgICBTdGRfUFBfM19TdHJhaWdodCArIAogICAgICAgICAgICAgIFN0ZF9QUF8yX1R1cm5pbmcgKwogICAgICAgICAgICAgIFN0ZF9QUF8zX1R1cm5pbmcgKwogICAgICAgICAgICAgICMgUFBfUHJpb3IgKwogICAgICAgICAgICAgIGZhY3RvcihBY3Rpdml0eUVuY29kZWQpLAogICAgICAgICAgICBkYXRhPWNvbWJpbmVkRGYsIHJhbmRvbSA9IH4xfGZhY3RvcihTdWJqZWN0KSwgbWV0aG9kID0gIlJFTUwiKQoKIyBhbm92YShtb2RlbCkKc3VtbWFyeShtb2RlbCkKcGxvdChtb2RlbCkKYGBgCgojIE5vIFJhbmRvbSBFZmZlY3RzCmBgYHtyfQpsaW5lYXJNb2RlbDEgPC0gbG0oUFBfQWZ0ZXIgfiAKICAgICAgICAgICAgICAgIE1lYW5fUFBfMl9BY2NIaWdoCiAgICAgICAgICAgICAgKyBNZWFuX1BQXzJfQWNjTG93CiAgICAgICAgICAgICAgKyBNZWFuX1BQXzNfQWNjSGlnaAogICAgICAgICAgICAgICsgTWVhbl9QUF8zX0FjY0xvdwogICAgICAgICAgICAgICsgU3RkX1BQXzJfQWNjSGlnaAogICAgICAgICAgICAgICsgU3RkX1BQXzJfQWNjTG93CiAgICAgICAgICAgICAgKyBTdGRfUFBfM19BY2NIaWdoCiAgICAgICAgICAgICAgKyBTdGRfUFBfM19BY2NMb3cKICAgICAgICAgICAgICAjICsgUFBfUHJpb3IKICAgICAgICAgICAgICArIGZhY3RvcihBY3Rpdml0eUVuY29kZWQpLAogICAgICAgICAgICBkYXRhPWNvbWJpbmVkRGYpCgojIGFub3ZhKG1vZGVsKQpzdW1tYXJ5KGxpbmVhck1vZGVsMSkKcGxvdChsaW5lYXJNb2RlbDEpCmBgYAoKCiMgV2l0aCBSYW5kb20gRWZmZWN0cwpgYGB7cn0KbGluZWFyTW9kZWwxIDwtIGxtZXIoUFBfQWZ0ZXIgfiAKICAgICAgICAgICAgICAgICgxIHwgU3ViamVjdCkKICAgICAgICAgICAgICArIE1lYW5fUFBfMl9BY2NIaWdoCiAgICAgICAgICAgICAgKyBNZWFuX1BQXzJfQWNjTG93CiAgICAgICAgICAgICAgKyBNZWFuX1BQXzNfQWNjSGlnaAogICAgICAgICAgICAgICsgTWVhbl9QUF8zX0FjY0xvdwogICAgICAgICAgICAgICsgU3RkX1BQXzJfQWNjSGlnaAogICAgICAgICAgICAgICsgU3RkX1BQXzJfQWNjTG93CiAgICAgICAgICAgICAgKyBTdGRfUFBfM19BY2NIaWdoCiAgICAgICAgICAgICAgKyBTdGRfUFBfM19BY2NMb3csCiAgICAgICAgICAgICAgIyArIGZhY3RvcihBY3Rpdml0eUVuY29kZWQpLAogICAgICAgICAgICBkYXRhPWNvbWJpbmVkRGYsIFJFTUwgPSBUKQoKIyBhbm92YShtb2RlbCkKc3VtbWFyeShsaW5lYXJNb2RlbDEpCnBsb3QobGluZWFyTW9kZWwxKQpgYGAKCgpgYGB7cn0KbGluZWFyTW9kZWwxIDwtIGxtKFBQX0FmdGVyIH4gCiAgICAgICAgICAgICAgICBNZWFuX1BQXzJfQWNjSGlnaAogICAgICAgICAgICAgICsgTWVhbl9QUF8yX0FjY0xvdwogICAgICAgICAgICAgICsgTWVhbl9QUF8zX0FjY0hpZ2gKICAgICAgICAgICAgICArIE1lYW5fUFBfM19BY2NMb3cKICAgICAgICAgICAgICAjICsgUFBfUHJpb3IKICAgICAgICAgICAgICArIGZhY3RvcihBY3Rpdml0eUVuY29kZWQpLCAKICAgICAgICAgICAgZGF0YT1jb21iaW5lZERmKQoKIyBhbm92YShtb2RlbCkKc3VtbWFyeShsaW5lYXJNb2RlbDEpCnBsb3QobGluZWFyTW9kZWwxKQpgYGAKCiMjIE1hY2hpbmUgTGVhcm5pbmcKCmBgYHtyfQpwcEFmdGVyIDwtIGNvbWJpbmVkRGYkUFBfQWZ0ZXIKcHBBZnRlckFycmF5IDwtIG1hdHJpeChwcEFmdGVyLCBucm93ID0gMSxuY29sID0gbGVuZ3RoKHBwQWZ0ZXIpKQogIAp0aHJlc2hvbGRQUEFmdGVyIDwtIG90c3UocHBBZnRlckFycmF5LCByYW5nZT1jKG1pbihwcEFmdGVyKSwgbWF4KHBwQWZ0ZXIpKSkgIyBFeHBlY3RlZCBUaHJlc2hvbGQgPiAwLjEwMTIzCnByaW50KHBhc3RlMCgnVGhyZXNob2xkOiAnLCB0aHJlc2hvbGRQUEFmdGVyKSkKCnNlbGVjdGVkRGYgPC0gY29tYmluZWREZiAlPiUgc2VsZWN0KAogICAgICAgICAgICAgICAgICAiU3ViamVjdCIsICJBY3Rpdml0eSIsICJQUF9BZnRlciIsICMgIlBQX1ByaW9yIiwKICAgICAgICAgICAgICAgICAgIk1lYW5fUFBfMl9BY2NIaWdoIiwgIk1lYW5fUFBfM19BY2NIaWdoIiwKICAgICAgICAgICAgICAgICAgIk1lYW5fUFBfMl9BY2NMb3ciLCAiTWVhbl9QUF8zX0FjY0xvdyIsCiAgICAgICAgICAgICAgICAgICJTdGRfUFBfMl9BY2NIaWdoIiwgIlN0ZF9QUF8zX0FjY0hpZ2giLAogICAgICAgICAgICAgICAgICAiU3RkX1BQXzJfQWNjTG93IiwgIlN0ZF9QUF8zX0FjY0xvdyIpCgpzZWxlY3RlZERmJFN1YmplY3QgPC0gTlVMTApzZWxlY3RlZERmJEFjdGl2aXR5X05PIDwtIGlmZWxzZShzZWxlY3RlZERmJEFjdGl2aXR5ID09ICJOTyIsIDEsIDApCnNlbGVjdGVkRGYkQWN0aXZpdHlfQyA8LSBpZmVsc2Uoc2VsZWN0ZWREZiRBY3Rpdml0eSA9PSAiQyIsIDEsIDApCnNlbGVjdGVkRGYkQWN0aXZpdHlfTSA8LSBpZmVsc2Uoc2VsZWN0ZWREZiRBY3Rpdml0eSA9PSAiTSIsIDEsIDApCnNlbGVjdGVkRGYkQWN0aXZpdHkgPC0gTlVMTAoKIyBzZWxlY3RlZERmJFBQX0Rldl8xX1R1cm5pbmcgPC0gTlVMTAojIHNlbGVjdGVkRGYkU3RkX1BQXzJfU3RyYWlnaHQgPC0gTlVMTAojIHNlbGVjdGVkRGYkU3RkX1BQXzJfVHVybmluZyA8LSBOVUxMCiMgc2VsZWN0ZWREZiRTdGRfUFBfM19TdHJhaWdodCA8LSBOVUxMCiMgc2VsZWN0ZWREZiRTdGRfUFBfM19UdXJuaW5nIDwtIE5VTEwKIyAKIyAjIEFjY29yZGluZyB0byBMaW5lYXIgbW9kZWwKIyBzZWxlY3RlZERmJFBQX0Rldl8yX1N0cmFpZ2h0IDwtIGFicyhzZWxlY3RlZERmJFBQX0Rldl8yX1N0cmFpZ2h0KQojIHNlbGVjdGVkRGYkUFBfRGV2XzNfU3RyYWlnaHQgPC0gYWJzKHNlbGVjdGVkRGYkUFBfRGV2XzNfU3RyYWlnaHQpCiMgc2VsZWN0ZWREZiRQUF9EZXZfMl9UdXJuaW5nIDwtIGFicyhzZWxlY3RlZERmJFBQX0Rldl8yX1R1cm5pbmcpCiMgc2VsZWN0ZWREZiRQUF9EZXZfM19UdXJuaW5nIDwtIGFicyhzZWxlY3RlZERmJFBQX0Rldl8zX1R1cm5pbmcpCiMgc2VsZWN0ZWREZiRQUF9QcmlvciA8LSBhYnMoc2VsZWN0ZWREZiRQUF9QcmlvcikgIyBOVUxMCgpzZWxlY3RlZERmJENsYXNzIDwtIGlmZWxzZShzZWxlY3RlZERmJFBQX0FmdGVyID49IHRocmVzaG9sZFBQQWZ0ZXIsIFQsIEYpCnNlbGVjdGVkRGYkUFBfQWZ0ZXIgPC0gTlVMTAoKcHJpbnQobmFtZXMoc2VsZWN0ZWREZikpCmBgYAoKYGBge3J9CiMgbGlicmFyeShtZWZhKQojIGNvbWJpbmVkRGYgPC0gcmVwKGNvbWJpbmVkRGYsIDEwKSAKYGBgCgpgYGB7cn0Kc2V0LnNlZWQoMzkpCm5fZm9sZHMgPC0gMTAKcGFyYW1zIDwtIHBhcmFtIDwtIGxpc3Qob2JqZWN0aXZlICAgICAgID0gImJpbmFyeTpsb2dpc3RpYyIsIAogICAgICAgICAgICAgICBib29zdGVyICAgICAgICAgID0gImdidHJlZSIsCiAgICAgICAgICAgICAgIGV2YWxfbWV0cmljICAgICAgPSAiYXVjIiwKICAgICAgICAgICAgICAgZXRhICAgICAgICAgICAgICA9IDAuMSwKICAgICAgICAgICAgICAgbWF4X2RlcHRoICAgICAgICA9IDEwLAogICAgICAgICAgICAgICBhbHBoYSAgICAgICAgICAgID0gMSwKICAgICAgICAgICAgICAgbGFtYmRhICAgICAgICAgICA9IDAsCiAgICAgICAgICAgICAgIGdhbW1hICAgICAgICAgICAgPSAwLjQ1LAogICAgICAgICAgICAgICBtaW5fY2hpbGRfd2VpZ2h0ID0gMC4zLAogICAgICAgICAgICAgICBzdWJzYW1wbGUgICAgICAgID0gMSwKICAgICAgICAgICAgICAgY29sc2FtcGxlX2J5dHJlZSA9IDEpCiAgICAgICAgICAgCiMgWEdCb29zdCBNb2RlbCAgICAgICAgIAp4Z2JfbSA8LSB4Z2IuY3YoICAgcGFyYW1zICAgICAgICAgICAgICAgPSBwYXJhbSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IGFzLm1hdHJpeChzZWxlY3RlZERmICU+JSBzZWxlY3QoLUNsYXNzKSkgLAogICAgICAgICAgICAgICAgICBsYWJlbCA9ICBzZWxlY3RlZERmJENsYXNzLAogICAgICAgICAgICAgICAgICBucm91bmRzICAgICAgICAgICAgID0gMTAwLAogICAgICAgICAgICAgICAgICB2ZXJib3NlICAgICAgICAgICAgID0gRiwKICAgICAgICAgICAgICAgICAgcHJlZGljdGlvbiAgICAgICAgICA9IFQsCiAgICAgICAgICAgICAgICAgIG1heGltaXplICAgICAgICAgICAgPSBGLCAjIENoYW5nZSB0aGlzIHZhbHVlIHRvIEYgd2lsbCBoZWxwIHRvIHJ1biB3aXRoIG1vcmUgaXRpbmVyYXRpb24KICAgICAgICAgICAgICAgICAgbmZvbGQgICAgICAgICAgICAgICA9IG5fZm9sZHMsCiAgICAgICAgICAgICAgICAgIG1ldHJpY3MgICAgICAgICAgICAgPSBjKCJhdWMiLCAiZXJyb3IiKSwKICAgICAgICAgICAgICAgICAgZWFybHlfc3RvcHBpbmdfcm91bmRzID0gNTAsCiAgICAgICAgICAgICAgICAgIHN0cmF0aWZpZWQgICAgICAgICAgICA9IFQsCiAgICAgICAgICAgICAgICAgIHNjYWxlX3Bvc193ZWlnaHQgICAgICA9IDEpCgojIHhnYl9tJGV2YWx1YXRpb25fbG9nW3hnYl9tJGJlc3RfaXRlcmF0aW9uLCJ0ZXN0X2F1Y19tZWFuIl0KeGdiX20kZXZhbHVhdGlvbl9sb2dbeGdiX20kYmVzdF9pdGVyYXRpb24sXQoKYGBgCgojIyBQZXJmb3JtYW5jZSBNZXRyaWNzCmBgYHtyfQojIFByZWRpY3Rpb24Kc2VsZWN0ZWREZiRjbHNQcmVkIDwtIHJvdW5kKHhnYl9tJHByZWQpCgpjb21wdXRlUGVyZm9ybWFuY2VSZXN1bHRzIDwtIGZ1bmN0aW9uKHNkYXQpewogIHNkYXQgPSBzZGF0W2NvbXBsZXRlLmNhc2VzKHNkYXQpLF0KICBhY2MgPSBzdW0oc2RhdFssMV0gPT0gc2RhdFssMl0pL25yb3coc2RhdCkKICBjb25mX21hdCA9IHRhYmxlKHNkYXQpCiAgc3BlY2lmID0gY29uZl9tYXRbMSwxXS9zdW0oY29uZl9tYXRbLDFdKQogIHNlbnNpdiA9IGNvbmZfbWF0WzIsMl0vc3VtKGNvbmZfbWF0WywyXSkKICBwcmVjaSA9ICBjb25mX21hdFsyLDJdL3N1bShjb25mX21hdFsyLF0pCiAgbnB2ID0gICAgY29uZl9tYXRbMSwxXS9zdW0oY29uZl9tYXRbMSxdKQogIHJldHVybihjKGFjYyxzcGVjaWYsc2Vuc2l2LHByZWNpLG5wdikpCn0KCiMgR2V0IGF2ZXJhZ2UgcGVyZm9ybWFuY2UKcGVyZm9ybWFuY2UgPC0gY29tcHV0ZVBlcmZvcm1hbmNlUmVzdWx0cyhzZWxlY3RlZERmICU+JSBzZWxlY3QoQ2xhc3MsIGNsc1ByZWQpKQphY2MgPC0gcGVyZm9ybWFuY2VbMV0KcHJlYyA8LSBwZXJmb3JtYW5jZVs0XQpyZWNhbGwgPC0gcGVyZm9ybWFuY2VbM10Kc3BlYyA8LSBwZXJmb3JtYW5jZVsyXQpucHYgPC0gcGVyZm9ybWFuY2VbNV0KZjEgPC0gKDIgKiByZWNhbGwgKiBwcmVjKSAvIChyZWNhbGwgKyBwcmVjKQphdWMgPC0gYXMubnVtZXJpYyh4Z2JfbSRldmFsdWF0aW9uX2xvZ1t4Z2JfbSRiZXN0X2l0ZXJhdGlvbiwgInRlc3RfYXVjX21lYW4iXSkKCnByaW50KHBhc3RlKCJBY2N1cmFjeT0iLCByb3VuZChhY2MsIDIpKSkKcHJpbnQocGFzdGUoIlByZWNpc2lvbj0iLCByb3VuZChwcmVjLCAyKSkpCnByaW50KHBhc3RlKCJSZWNhbGw9Iiwgcm91bmQocmVjYWxsLCAyKSkpCnByaW50KHBhc3RlKCJTcGVjaWZpY2l0eT0iLCByb3VuZChzcGVjLCAyKSkpCnByaW50KHBhc3RlKCJOUFY9Iiwgcm91bmQobnB2LCAyKSkpCnByaW50KHBhc3RlKCJGMT0iLCByb3VuZChmMSwgMikpKQpwcmludChwYXN0ZSgiQVVDPSIsIHJvdW5kKGF1YywgMikpKQpgYGAKCmBgYHtyfQojIEltcG9ydGFuY2UKYnN0IDwtIHhnYm9vc3QoICAgcGFyYW1zICAgICAgICAgICAgICAgPSBwYXJhbSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IGFzLm1hdHJpeChzZWxlY3RlZERmICU+JSBzZWxlY3QoLWMoQ2xhc3MsIGNsc1ByZWQpKSkgLAogICAgICAgICAgICAgICAgICBsYWJlbCA9ICBzZWxlY3RlZERmJENsYXNzLAogICAgICAgICAgICAgICAgICBucm91bmRzICAgICAgICAgICAgID0gMTAwLAogICAgICAgICAgICAgICAgICB2ZXJib3NlICAgICAgICAgICAgID0gRiwKICAgICAgICAgICAgICAgICAgcHJlZGljdGlvbiAgICAgICAgICA9IFQsCiAgICAgICAgICAgICAgICAgIG1heGltaXplICAgICAgICAgICAgPSBGLCAjIENoYW5nZSB0aGlzIHZhbHVlIHRvIEYgd2lsbCBoZWxwIHRvIHJ1biB3aXRoIG1vcmUgaXRpbmVyYXRpb24KICAgICAgICAgICAgICAgICAgbmZvbGQgICAgICAgICAgICAgICA9IG5fZm9sZHMsCiAgICAgICAgICAgICAgICAgIG1ldHJpY3MgICAgICAgICAgICAgPSBjKCJhdWMiLCAiZXJyb3IiKSwKICAgICAgICAgICAgICAgICAgZWFybHlfc3RvcHBpbmdfcm91bmRzID0gNTAsCiAgICAgICAgICAgICAgICAgIHN0cmF0aWZpZWQgICAgICAgICAgICA9IFQsCiAgICAgICAgICAgICAgICAgIHNjYWxlX3Bvc193ZWlnaHQgICAgICA9IDEpCmltcG9ydGFuY2VEZiA8LSB4Z2IuaW1wb3J0YW5jZShjb2xuYW1lcyhzZWxlY3RlZERmICU+JSBzZWxlY3QoLWMoQ2xhc3MsIGNsc1ByZWQpKSksIG1vZGVsID0gYnN0KQpwcmludChpbXBvcnRhbmNlRGYpCmBgYAoKYGBge3J9CmxpYnJhcnkocFJPQykKCmRmUk9DIDwtIHBST0M6OnJvYyhyZXNwb25zZSA9IGlmZWxzZShzZWxlY3RlZERmJENsYXNzPT1ULCAxLCAwKSwKICAgICAgICAgICAgICAgcHJlZGljdG9yID0gcm91bmQoeGdiX20kcHJlZCksCiAgICAgICAgICAgICAgIGxldmVscz1jKDAsIDEpLCBkaXJlY3Rpb24gPSAiPCIpCgojIGl0ID0gd2hpY2gubWF4KHhnYl9tJGV2YWx1YXRpb25fbG9nJHRlc3RfYXVjX21lYW4pCiMgYmVzdC5pdGVyID0geGdiX20kZXZhbHVhdGlvbl9sb2ckaXRlcltpdF0KIyBiZXN0Lml0ZXIgCgpwbG90KHBST0M6OnJvYyhyZXNwb25zZSA9IGlmZWxzZShzZWxlY3RlZERmJENsYXNzPT1ULCAxLCAwKSwKICAgICAgICAgICAgICAgcHJlZGljdG9yID0gcm91bmQoeGdiX20kcHJlZCksCiAgICAgICAgICAgICAgIGxldmVscz1jKDAsIDEpLCBkaXJlY3Rpb24gPSAiPCIpLCAKICAgICBsZWdhY3kuYXhlcyA9IFRSVUUsCiAgICAgbWFpbj0iUk9DIEN1cnZlIiwgCiAgICAgbHdkPTEuNSkgCmBgYAoKCiMjIyBQbG90IGZlYXR1cmUgaW1wb3J0YW5jZQpgYGB7cn0KeUF4aXMgPC0gbGlzdCgKICB0aXRsZSA9ICdJbXBvcnRhbmNlJywKICByYW5nZT1jKDAuMCwgMS4wKQopCnhBeGlzIDwtIGxpc3QoCiAgdGl0bGUgPSAnJwopCgppbXBvcnRhbmNlRGYkRmVhdHVyZSA8LSBmYWN0b3IoaW1wb3J0YW5jZURmJEZlYXR1cmUsIGxldmVscyA9IGltcG9ydGFuY2VEZltvcmRlcigtR2FpbiksXSRGZWF0dXJlKQpmaWdfSW1wb3J0YW5jZSA8LSBwbG90X2x5KGltcG9ydGFuY2VEZiwgeCA9IH5GZWF0dXJlLCB5ID0gfkdhaW4sIHR5cGUgPSAnYmFyJywgbmFtZSA9ICdHYWluJywgd2lkdGg9NjAwKSAlPiUKICBhZGRfdHJhY2UoeSA9IH5Db3ZlciwgbmFtZSA9ICdDb3ZlcicpICU+JSAKICBhZGRfdHJhY2UoeSA9IH5GcmVxdWVuY3ksIG5hbWUgPSAnRnJlcXVlbmN5JykgJT4lIAogIGxheW91dCh5YXhpcyA9IHlBeGlzLCB4YXhpcz14QXhpcywgYmFybW9kZSA9ICdncm91cCcsIHRpdGxlPSJGZWF0dXJlIEltcG9ydGFuY2UiKSAlPiUgCiAgY29uZmlnKC5MYXN0LnZhbHVlLCBtYXRoamF4ID0gJ2NkbicpCgpodG1sdG9vbHM6OnRhZ0xpc3QoZmlnX0ltcG9ydGFuY2UpCmBgYAoKCg==